package com.jinlong.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jinlong.annotation.MyAutowired;
import com.jinlong.annotation.MyController;
import com.jinlong.annotation.MyRequestMapping;
import com.jinlong.annotation.MyRequestParam;
import com.jinlong.annotation.MyService;
import com.jinlong.controller.MainController;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
public class DispatcherServlet extends HttpServlet{
	
	List<String>classNames = new ArrayList<String>();
	Map<String,Object> beans = new HashMap<String,Object>();
	Map<String,Object> handlerMap = new HashMap<String,Object>();
    //init方法是为了初始化sping容器，实例化bean
    @Override
    public void init(ServletConfig config) throws ServletException {
    	//扫描
    	scanPackage("com.jinlong");
    	doInstance();
    	doAutowired();
    	urlMapping();
    }

    private void urlMapping() {
		for(Map.Entry<String, Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();
			Class<?> clazz = instance.getClass();
			if(clazz.isAnnotationPresent(MyController.class)) {
				MyRequestMapping myRequestMapping = clazz.getAnnotation(MyRequestMapping.class);
				String classPath = myRequestMapping.value();
				Method[] methods = clazz.getMethods();
				for(Method method : methods) {
					if(method.isAnnotationPresent(MyRequestMapping.class)) {
						MyRequestMapping mreq = method.getAnnotation(MyRequestMapping.class);
						String mothodPath = mreq.value();
						
						handlerMap.put(classPath+mothodPath, method);
					}else {
						continue;
					}
				}
			}
		}
		
	}

	private void doAutowired() {
		for(Map.Entry<String, Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();
			Class<?> clazz = instance.getClass();
			if(clazz.isAnnotationPresent(MyController.class)) {
				Field [] fields = clazz.getDeclaredFields();
				for(Field field :fields) {
					if(field.isAnnotationPresent(MyAutowired.class)) {
						MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
						String key = myAutowired.value();
						field.setAccessible(true);
						try {
							field.set(instance, beans.get(key));
						} catch (IllegalArgumentException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}else {
						continue;
					}
				}
			}else {
				continue;
			}
		}
		
	}

	private void doInstance() {
		for(String className : classNames) {
			String cn = className.replace(".class", "");
			try {
				Class<?> clazz = Class.forName(cn);
				
				if(clazz.isAnnotationPresent(MyController.class)) {
					//如果为true这说明传进来的就是一个控制类
					Object instance = clazz.newInstance();
					MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
					String key = requestMapping.value();
					beans.put(key, instance);
				}else if(clazz.isAnnotationPresent(MyService.class)) {
					//如果为true这说明传进来的就是一个service
					Object instance1 = clazz.newInstance();
					MyService service = clazz.getAnnotation(MyService.class);
					String key1 = service.value();
					beans.put(key1, instance1);
				}else {
					continue;
				}
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}  catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

	private void scanPackage(String basePackage) {
		URL url = this.getClass().getClassLoader().getResource("/"+basePackage.replaceAll("\\.", "/"));
		String fileStr = url.getFile();
		File file = new File(fileStr);
		String[] filesStr = file.list();
		for(String path : filesStr) {
			File filePath = new File(fileStr+path);
			if(filePath.isDirectory()) {
				scanPackage(basePackage+"."+path);
			}else {
				classNames.add(basePackage+"."+filePath.getName());
			}
		}
	}

	//业务请求代码
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri = req.getRequestURI();
        
        String context = req.getContextPath();
        
        String path = uri.replace(context, "");
        Method method =(Method) handlerMap.get(path);
        
        MainController instance = (MainController)beans.get("/"+path.split("/")[1]);
        
        Object args[] = hand(req, resp, method);
        
        try {
			method.invoke(instance, args);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //this.doGet(req, resp);
    	this.doPost(req, resp);
    }
    
    private static Object[] hand(HttpServletRequest request,HttpServletResponse response,Method method) {
		Class<?>[] paramClazzs = method.getParameterTypes();
		Object[] args = new Object[paramClazzs.length];
		int args_i = 0;
		int index = 0;
		for(Class<?> paramClass : paramClazzs){
			if(ServletRequest.class.isAssignableFrom(paramClass)) {
				args[args_i++] = request;
			}
			if(ServletResponse.class.isAssignableFrom(paramClass)) {
				args[args_i++] = response;
			}
			Annotation[] paramAns = method.getParameterAnnotations()[index];
			if(paramAns.length>0) {
				for(Annotation paramAn : paramAns) {
					if(MyRequestParam.class.isAssignableFrom(paramAn.getClass())) {
						MyRequestParam myRequestParam =(MyRequestParam) paramAn;
						args[args_i++] = request.getParameter(myRequestParam.value());
					}
				}
			}
			index++;
		}
		return args;
	}
}
